package org.atlantis.evnlib;

import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.atlantis.evnlib.exception.EventException;
import org.atlantis.evnlib.execution.EventExecutor;
import org.atlantis.evnlib.internal.SetMap;
import org.atlantis.evnlib.internal.SetMap.Pair;

/**
 * 事件处理器。
 * 
 * @author <a href="mailto:seenoevil.cn@gmail.com">李曦</a><br/>
 *         Created at: 2011-7-4 上午09:53:24
 */
class EventProcessor {

	private final ConcurrentMap<String, Event> evnStore = new ConcurrentHashMap<String, Event>();
	private final ReceiverFinder finder = new AnnotationReceiverFinder();
	private final EventExecutor evnExec;

	EventProcessor(EventExecutor evnExec) {
		this.evnExec = evnExec;
	}

	/** 注册监听器 */
	void register(Object listener) {
		SetMap<String, EventReceiver> receivers = finder.scan(listener);
		for (Pair<String, EventReceiver> receiver : receivers) {
			Event event = evnStore.get(receiver.key);
			if (event == null) throw new EventException("No Event<%s> found to listen for listener %s.", receiver.key,
					listener);
			event.addReceivers(receiver.value);
		}
	}

	/** 删除监听器 */
	void unregister(Object listener) {
		SetMap<String, EventReceiver> receivers = finder.scan(listener);
		for (Pair<String, EventReceiver> receiver : receivers) {
			Event event = evnStore.get(receiver.key);
			if (event == null) continue;
			event.removeReceivers(receiver.value);
		}
	}

	/** 注销事件处理器 */
	Collection<Runnable> shutdownNow() {
		return evnExec.shutdownNow();
	}

	void addEvent(EventDef eventDef) {
		String eventName = eventDef.getEventName();
		if (evnStore.containsKey(eventName)) return;
		Event event = new Event(eventDef, evnExec);
		evnStore.putIfAbsent(eventName, event);
		evnExec.addEvent(new EventProxy(event));
	}

	// TODO 还没想好可以随意修改事件（增加、删除）的逻辑
	Collection<Runnable> removeEvent(String eventName) {
		Event event = evnStore.remove(eventName);
		if (event == null) return null;
		return evnExec.removeEvent(new EventProxy(event));
	}

	void fireEvent(EventArg eventArg) {
		Event event = evnStore.get(eventArg.getEventName());
		if (event == null) throw new EventException("No Event<%s> found to fire.", eventArg.getEventName());
		event.fire(eventArg);
	}
}
